package net.zoneland.zrdp.framework.web.service.impl;

import net.zoneland.zrdp.common.config.ZonevueConfig;
import net.zoneland.zrdp.common.core.domain.entity.SysUser;
import net.zoneland.zrdp.common.utils.JacksonUtils;
import net.zoneland.zrdp.common.utils.httpClient.HttpClientUtils;
import net.zoneland.zrdp.framework.web.service.HttpClientService;
import net.zoneland.zrdp.system.domain.bean.LoginedUser;
import net.zoneland.zrdp.system.service.ISysUserService;
import net.zoneland.zrdp.system.service.mapstruct.UserConverter;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.regex.Matcher;

/**
 * http服务实现
 */
@Service
public class HttpClientServiceImpl implements HttpClientService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientServiceImpl.class);

    // 默认通用角色的id
    private static final Long COMMON_ROLE_ID = 2L;
    /**
     * 公共httpClient服务连接池
     */
    @Resource(name = "commonHttpClientPoolExecutor")
    private CloseableHttpClient commonHttpClientPoolExecutor;

    /**
     * 读取项目相关配置
     */
    @Resource
    private ZonevueConfig zonevueConfig;

    @Resource
    private ISysUserService userService;

    /**
     * 获取当前登录用户id
     * @param cookie 原请求cookie
     * @return 当前登录用户id
     */
    @Override
    public String getLoginedUserId(final String cookie) {
        if (cookie == null || !cookie.contains("loginCenterCookieToken")) {
            LOGGER.info("Cookie信息错误：cookie: {}", cookie);
            return null;
        }

        // 获取当前用户对象
        final LoginedUser loginedUserInfo = getLoginedUserInfo(cookie);
        if (loginedUserInfo == null) {
            LOGGER.error("获取当前登录用户信息失败，cookie: {}", cookie);
            return null;
        }

        final SysUser dbuser = userService.selectUserByUserName(loginedUserInfo.getUid());
        // 看用户是否存在，如果不存在把用户信息保存到表中。
        if (dbuser == null) {
            final SysUser user = UserConverter.INSTANCE.loginedUserToSysUser(loginedUserInfo);
            // 设置新增用户的基础角色（默认通用角色）
            user.setRoleIds(new Long[]{COMMON_ROLE_ID});
            userService.insertUser(user);
        } else { // 更新用户信息
            UserConverter.INSTANCE.updateUserFromLoginedUser(loginedUserInfo, dbuser);
            userService.updateUserOnly(dbuser);
        }
        return loginedUserInfo.getUid();

    }

    /**
     * 获取当前登录用户信息
     * @param cookie 原请求cookie
     * @return 用户信息json字符串
     */
    @Override
    public LoginedUser getLoginedUserInfo(final String cookie) {
        // 构建http请求对象
        final HttpGet get = new HttpGet(zonevueConfig.getSsoWebLoginedUserUrl());
        get.addHeader(new BasicHeader(HttpClientUtils.HEADER_KEY_COOKIE, cookie));
        // 执行请求
        try (final CloseableHttpResponse response = commonHttpClientPoolExecutor.execute(get)) {
            // 请求状态码
            final int statusCode = response.getStatusLine().getStatusCode();
            // 请求状态不为200，请求失败
            if (statusCode != HttpStatus.SC_OK) {
                LOGGER.error("请求失败，当前statusCode：{}，url：{}", statusCode, zonevueConfig.getSsoWebLoginedUserUrl());
                return null;
            }
            final HttpEntity entity = response.getEntity();
            final long contentLength = entity.getContentLength();
            // 判断返回内容是否超过最大限制
            if (contentLength > HttpClientUtils.HTTP_CONTENT_LENGTH_MAX) {
                LOGGER.error("获取当前登录用户信息返回内容超过最大限制，请求地址：{}，请求cookies：{}，最大限制：{}，实际长度：{}",
                    zonevueConfig.getSsoWebLoginedUserUrl(), cookie, HttpClientUtils.HTTP_CONTENT_LENGTH_MAX, contentLength);
                return null;
            }
            final ContentType contentType = ContentType.getOrDefault(entity);
            // 获取内容字节数组（因为这里只是获取登录用户信息，数据量比较少，所以直接获取接口返回的内容字节数组）
            final byte[] content = EntityUtils.toByteArray(entity);
            // 获取字符集
            final Charset charset = getLoginedUserInfoCharset(contentType, content);
            // 内容字节数组转换为指定字符集字符串
            return JacksonUtils.toObject(new String(content, charset), LoginedUser.class);
        } catch (final IOException e) {
            LOGGER.error("获取当前登录用户信息失败，请求地址：{}，请求cookies：{}", zonevueConfig.getSsoWebLoginedUserUrl(), cookie, e);
            return null;
        }

    }

    /**
     * 获取当前登录用户信息数据字符集
     * @param contentType 内容类型
     * @param content 内容字节数组
     * @return 字符集
     */
    private Charset getLoginedUserInfoCharset(final ContentType contentType, final byte[] content) {
        final Charset charset = contentType.getCharset();
        if (Objects.nonNull(charset)) {
            return charset;
        }
        // 使用默认编码转成字符串，并且用正则匹配
        final Matcher matcher = HttpClientUtils.PATTERN_META_CHARSET.matcher(new String(content));
        // 匹配到只有一组数据时，使用第一组字符串数据作为字符集
        if (matcher.find() && matcher.groupCount() == 1) {
            return Charset.forName(matcher.group(1));
        }
        // 否则默认使用ISO-8859-1字符集
        return StandardCharsets.ISO_8859_1;
    }

}
